;; Tests of the Non-robust computational geometry functions
;; Copyright (C) 2021  Rocks Mazama
;; 
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; 
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;; 
;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <https://www.gnu.org/licenses/>.

(ns mazama.compgeom.segment-intersection-test
  (:require
   [clojure.test :refer [deftest is testing]]
   [mazama.compgeom.core :refer [parametric-line]]
   [mazama.compgeom.segment-intersection :refer :all]))

;;;; NOTICE
;;;;
;;;; It is assumed that
;;;; the x-axis increases to the right and
;;;; the y-axis increases DOWNWARD

(deftest segment-intersection-test
  (testing "bounding boxes do not intersect"
    (let [a [0 0]
          b [1 1]
          c [4 2]
          d [3 3]
          result (segment-intersection a b c d)]
      (is (nil? result)))
    (let [a [7 8]
          b [5 9]
          c [6 0]
          d [8 1]
          result (segment-intersection a b c d)]
      (is (nil? result)))
    (let [a [7 8]
          b [5 9]
          c [9 10]
          d [8 6]
          result (segment-intersection a b c d)]
      (is (nil? result)))
    (testing "bounding boxes do not intersect colinear"
      (let [a [2 1]
            b [3 -4]
            eq (parametric-line a b)
            c (eq 200201/200200)
            d (eq 2)
            result (segment-intersection a b c d)]
        (is (nil? result)))))
  (testing "bounding boxes do intersect but the segments do not"
    (let [a [5 2]
          b [3 2]
          c [4 4]
          d [1 1]
          result (segment-intersection a b c d)]
      (is (nil? result)))
    (testing "degenerate"
      (let [a [5 3]
            b [7 8]
            c [6 6]]
        (is (nil? (segment-intersection a b c c)))
        (is (nil? (segment-intersection b a c c)))
        (is (nil? (segment-intersection c c a b)))
        (is (nil? (segment-intersection c c b a))))))
  (testing "colinear overlap"
    (testing "colinear overlap 1"
      (let [a [1 2]
            b [3 -4]
            eq (parametric-line a b)
            c (eq -1)
            d (eq 1/3)
            result (segment-intersection a b c d)
            code (:code result)]
        (is (= code :colinear-overlap))))
    (testing "colinear overlap 2"
      (let [a [1 2]
            b [3 -4]
            eq (parametric-line a b)
            c (eq 1/4)
            d (eq 3/5)
            result (segment-intersection a b c d)
            code (:code result)]
        (is (= code :colinear-overlap))))
    (testing "colinear overlap 3"
      (let [a [1 2]
            b [3 -4]
            eq (parametric-line a b)
            c (eq -1/4)
            d (eq 5/3)
            result (segment-intersection a b c d)
            code (:code result)]
        (is (= code :colinear-overlap))))
    (testing "colinear overlap 4"
      (let [a [22 10]
            b [37 -4]
            eq (parametric-line a b)
            c (eq 15/16)
            d (eq 5/3)
            result (segment-intersection a b c d)
            code (:code result)]
        (is (= code :colinear-overlap)))))
  (testing "vertex intersection"
    (testing "vertex intersection degenerate 1"
      (let [a [3 -5]
            result (segment-intersection a a a a)
            code (:code result)
            [x y] (:point result)]
        (is (= code :vertex))
        (is (== x (a 0)))
        (is (== y (a 1)))))
    (testing "vertex intersection degenerate 2"
      (let [a [3 -5]
            b [0 0]
            result (segment-intersection a b a a)
            code (:code result)
            [x y] (:point result)]
        (is (= code :vertex))
        (is (== x (a 0)))
        (is (== y (a 1)))))
    (testing "vertex intersection degenerate 3"
      (let [a [-13 -5]
            b [10 0]
            result (segment-intersection a a a b)
            code (:code result)
            [x y] (:point result)]
        (is (= code :vertex))
        (is (== x (a 0)))
        (is (== y (a 1)))))
    (testing "vertex intersection degenerate 4"
      (let [a [3 -5]
            b [0 0]
            result (segment-intersection a b b b)
            code (:code result)
            [x y] (:point result)]
        (is (= code :vertex))
        (is (== x (b 0)))
        (is (== y (b 1)))))
    (testing "vertex intersection degenerate 5"
      (let [a [-13 -5]
            b [10 0]
            result (segment-intersection b b a b)
            code (:code result)
            [x y] (:point result)]
        (is (= code :vertex))
        (is (== x (b 0)))
        (is (== y (b 1)))))
    (testing "vertex intersection colinear 1"
      (let [a [1 2]
            b [3 -4]
            eq (parametric-line a b)
            c (eq -1)
            result (segment-intersection a b a c)
            code (:code result)
            [x y] (:point result)]
        (is (= code :vertex))
        (is (== x (a 0)))
        (is (== y (a 1)))))
    (testing "vertex intersection colinear 2"
      (let [a [-3 -2]
            b [7 0]
            eq (parametric-line a b)
            c (eq 5/2)
            result (segment-intersection a b b c)
            code (:code result)
            [x y] (:point result)]
        (is (= code :vertex))
        (is (== x (b 0)))
        (is (== y (b 1)))))
    (testing "vertex intersection rational"
      (let [a [3 2]
            b [1 22/7]
            c [1 22/7]
            d [-7 7]
            result (segment-intersection a b c d)
            code (:code result)
            [x y] (:point result)]
        (is (= code :vertex))
        (is (== x 1))
        (is (== y 22/7)))))
  (testing "proper intersection"
    (testing "proper intersection degenerate 1"
      (let [a [-3 -1]
            b [-2/3 7/2]
            eq (parametric-line a b)
            c (eq 3/7)
            result (segment-intersection a b c c)
            code (:code result)
            [x y] (:point result)]
        (is (= code :proper))
        (is (== x (c 0)))
        (is (== y (c 1)))))
    (testing "proper intersection degenerate 2"
      (let [a [-1 -3]
            b [-2/7 3/2]
            eq (parametric-line a b)
            c (eq 1/10)
            result (segment-intersection c c a b)
            code (:code result)
            [x y] (:point result)]
        (is (= code :proper))
        (is (== x (c 0)))
        (is (== y (c 1)))))
    (testing "proper intersection rational"
      (let [a [-3 -1]
            b [-2/3 7/2]
            c [1 -2]
            d [-9/4 5/3]
            result (segment-intersection a b c d)
            code (:code result)
            [x y] (:point result)]
        (is (= code :proper))
        (is (== x -3089/1669))
        (is (== y 2030/1669)))))
  )
